
Imports System
Imports System.Collections
Imports System.Data
Imports System.Data.SqlClient
Imports System.Diagnostics
Imports System.Security.Cryptography
Imports System.Text
Imports _2bMatesSite.Common

Imports System.Web.Security
Imports System.Web

Namespace _2bMatesSite.BO
	''' <summary>
	''' Users releated utilities and classes.
	''' </summary>
	Public Class Users
		'
		' Public constants
		'

		Public Const STATUS_UNCONFIRMED As Integer = 0
		Public Const STATUS_ACTIVE As Integer = 1
		Public Const STATUS_LOCKED As Integer = 2
		Public Const STATUS_ADMIN As Integer = 3
		Public Const FORUM_APPROVED As Integer = 2


		' Returns the User upon success, null otherwise
		Public Shared Function Login(ByVal userEmail As String, ByVal userPass As String) As User
			Dim cmd As New SqlCommand("SELECT * FROM Users WHERE Email=@email")
			cmd.Parameters.Add("@email", userEmail.ToLower())

			UpdateUserEmailToLower(userEmail, userPass)

			Dim passHash As String = ComputeUserHash(userEmail.ToLower(), userPass)
			Dim usr As User = LoginUserByCmdPassHash(cmd, passHash)

			If (Constants.HAS_FORUM = Constants.SHOW_ON) AndAlso (usr <> Nothing) Then
				LoginForumUser(userEmail.ToLower(), userPass)
			End If

			If usr <> Nothing Then
				Dim idName As String = String.Format("{0};{1};{2}", usr.ID, Constants.FORUM_BOARD_ID, usr.Email)
				FormsAuthentication.SetAuthCookie(idName, False)
			End If

			Return usr
		End Function

		Public Shared Function LoginWithPassHash(ByVal userEmail As String, ByVal passHash As String) As User
			Dim cmd As New SqlCommand("SELECT * FROM Users WHERE Email=@email")
			cmd.Parameters.Add("@email", userEmail)

			Dim usr As User = LoginUserByCmdPassHash(cmd, passHash)

			If (Constants.HAS_FORUM = Constants.SHOW_ON) AndAlso (usr <> Nothing) Then
				LoginForumUser(userEmail, usr.PassHash)
			End If

			If usr <> Nothing Then
				Dim idName As String = String.Format("{0};{1};{2}", usr.ID, Constants.FORUM_BOARD_ID, usr.Email)
				FormsAuthentication.SetAuthCookie(idName, False)
			End If

			Return usr
		End Function

		' Find a user by it's email
		' returns null if the user was not found
		Public Shared Function GetUserByEmail(ByVal userEmail As String) As User
			Dim cmd As New SqlCommand("SELECT * FROM Users WHERE Email=@email")
			cmd.Parameters.Add("@email", userEmail)

			Return GetUserByCmd(cmd)
		End Function


		' Find a user by it's ID
		' returns null if the user was not found
		Public Shared Function GetUserByID(ByVal userID As Integer) As User
			Dim cmd As New SqlCommand("SELECT * FROM Users WHERE ID=@userID")
			cmd.Parameters.Add("@userID", userID)

			Return GetUserByCmd(cmd)
		End Function

		' Send a notification of a confirmed friendship
		Public Shared Sub SendNewFriendshipNotification(ByVal request As DirectFriend)
			Dim fromUser As User = Nothing
			Dim toUser As User = Nothing

			If request.InviterID = request.UserID Then
				fromUser = request.[Friend]
				toUser = Users.GetUserByID(request.UserID)
			Else
				fromUser = Users.GetUserByID(request.UserID)
				toUser = request.[Friend]
			End If

			If Not toUser.EnableEmailNotify Then
				Return
			End If

			Dim from As String = Constants.MESSAGES_EMAIL
			Dim [to] As String = "<" + toUser.Email + ">"

			' subject...
			Dim subj As String = Constants.NOTIFY_NEW_FRIEND_SUBJECT.Replace(Constants.TXT_USER_NAME_TAG, fromUser.Name)

			' body...
			Dim body As String = Constants.NOTIFY_NEW_FRIEND_BODY.Replace(Constants.TXT_USER_NAME_TAG, fromUser.Name)

			' No SPAM disclaimer
			body = body.Replace(Constants.TXT_DISCLAIMER_TEXT_TAG, ComposeNoSPAMDisclaimer(toUser))

			' De send the mail
			Utils.SendMail(from, [to], subj, body)
		End Sub

		' Send a notification of a friendship request
		Public Shared Sub SendFriendshipRequestNotification(ByVal request As DirectFriend)
			Dim fromUser As User = Nothing
			Dim toUser As User = Nothing

			If request.InviterID = request.UserID Then
				fromUser = Users.GetUserByID(request.UserID)
				toUser = request.[Friend]
			Else
				fromUser = request.[Friend]
				toUser = Users.GetUserByID(request.UserID)
			End If

			Dim from As String = Constants.MESSAGES_EMAIL
			Dim [to] As String = "<" + toUser.Email + ">"

			' subject...
			Dim subj As String = Constants.NOTIFY_FRIEND_REQUEST_SUBJECT.Replace(Constants.TXT_USER_NAME_TAG, fromUser.Name)

			' body...
			Dim body As String = Constants.NOTIFY_FRIEND_REQUEST_BODY.Replace(Constants.TXT_USER_NAME_TAG, fromUser.Name)
			body = body.Replace(Constants.TXT_USER_EMAIL_TAG, fromUser.Email)

			' Friendship request link
			body = body.Replace(Constants.TXT_FRIENDSHIP_REQUEST_LINK_TAG, ComposeFriendRequestLink(request) + "&" + ComposeURLLoginParams(toUser))

			' No SPAM disclaimer
			body = body.Replace(Constants.TXT_DISCLAIMER_TEXT_TAG, ComposeNoSPAMDisclaimer(toUser))

			' De send the mail
			Utils.SendMail(from, [to], subj, body)
		End Sub

		' Send a notification of a new message
		Public Shared Sub SendMailNotification(ByVal toUser As User, ByVal fromUser As User, ByVal msgID As Integer, ByVal msgType As Messages.MessageType)
			If Not toUser.EnableEmailNotify Then
				Return
			End If

			Dim from As String = Constants.MESSAGES_EMAIL
			Dim [to] As String = "<" + toUser.Email + ">"
			Dim subj As String = ""
			Dim body As String = ""

			Select Case msgType
				Case Messages.MessageType.mtBulletin
					subj = Constants.NOTIFY_NEW_BULLETIN_SUBJECT
					body = Constants.NOTIFY_NEW_BULLETIN_BODY
					Exit Select
				Case Messages.MessageType.mtGroupMessage

					subj = Constants.NOTIFY_NEW_GROUP_MAIL_SUBJECT
					body = Constants.NOTIFY_NEW_GROUP_MAIL_BODY
					Exit Select
				Case Else

					subj = Constants.NOTIFY_NEW_MAIL_SUBJECT
					body = Constants.NOTIFY_NEW_MAIL_BODY
					Exit Select
			End Select

			' subject...
			subj = subj.Replace(Constants.TXT_USER_NAME_TAG, fromUser.Name)

			' body...
			body = body.Replace(Constants.TXT_USER_NAME_TAG, fromUser.Name)

			' Message link
			body = body.Replace(Constants.TXT_MAIL_LINK_TAG, ComposeMailLink(msgID) + "&" + ComposeURLLoginParams(toUser))

			' No SPAM disclaimer
			body = body.Replace(Constants.TXT_DISCLAIMER_TEXT_TAG, ComposeNoSPAMDisclaimer(toUser))

			' Send the mail
			Utils.SendMail(from, [to], subj, body)
		End Sub

		' Send a notification of a new user's comment
		Public Shared Sub SendUserCommentNotification(ByVal toUser As User, ByVal fromUser As User)
			If Not toUser.EnableEmailNotify Then
				Return
			End If

			Dim from As String = Constants.MESSAGES_EMAIL
			Dim [to] As String = "<" + toUser.Email + ">"
			Dim subj As String = Constants.NOTIFY_NEW_USER_COMMENT_SUBJECT
			Dim body As String = Constants.NOTIFY_NEW_USER_COMMENT_BODY

			' body...
			body = body.Replace(Constants.TXT_USER_NAME_TAG, fromUser.Name)

			' User comment link
			body = body.Replace(Constants.TXT_COMMENT_LINK_TAG, ComposeCommentLink() + "?" + ComposeURLLoginParams(toUser))

			' No SPAM disclaimer
			body = body.Replace(Constants.TXT_DISCLAIMER_TEXT_TAG, ComposeNoSPAMDisclaimer(toUser))

			' Do send the mail
			Utils.SendMail(from, [to], subj, body)
		End Sub

		' Send a notification of a updated blog comment
		Public Shared Sub SendBlogUpdateNotification(ByVal toUser As User, ByVal be As Blog)
			If Not toUser.EnableEmailNotify Then
				Return
			End If

			Dim from As String = Constants.MESSAGES_EMAIL
			Dim [to] As String = "<" + toUser.Email + ">"
			Dim subj As String = Constants.NOTIFY_UPDATED_BLOG_SUBJECT

			' Blog sender user name
			Dim blogSender As User = be.Sender
			Dim body As String = Constants.NOTIFY_UPDATED_BLOG_BODY.Replace(Constants.TXT_USER_NAME_TAG, blogSender.Name)

			' Blog link
			body = body.Replace(Constants.TXT_BLOG_LINK_TAG, ComposeBlogLink(be) + "&" + ComposeURLLoginParams(toUser))

			' No SPAM disclaimer
			body = body.Replace(Constants.TXT_DISCLAIMER_TEXT_TAG, ComposeNoSPAMDisclaimer(toUser))

			' Do send the mail
			Utils.SendMail(from, [to], subj, body)
		End Sub

		' Send a notification of a new blog comment
		Public Shared Sub SendBlogNotification(ByVal toUser As User, ByVal be As Blog)
			If Not toUser.EnableEmailNotify Then
				Return
			End If

			Dim from As String = Constants.MESSAGES_EMAIL
			Dim [to] As String = "<" + toUser.Email + ">"
			Dim subj As String = Constants.NOTIFY_NEW_BLOG_SUBJECT

			' Blog sender user name
			Dim blogSender As User = be.Sender
			Dim body As String = Constants.NOTIFY_NEW_BLOG_BODY.Replace(Constants.TXT_USER_NAME_TAG, blogSender.Name)

			' Blog link
			body = body.Replace(Constants.TXT_BLOG_LINK_TAG, ComposeBlogLink(be) + "&" + ComposeURLLoginParams(toUser))

			' No SPAM disclaimer
			body = body.Replace(Constants.TXT_DISCLAIMER_TEXT_TAG, ComposeNoSPAMDisclaimer(toUser))

			' Do send the mail
			Utils.SendMail(from, [to], subj, body)
		End Sub

		' Send an invitation to a friend to join 2bm
		' NOTE: throws an exception on error (e.g. if the email was wrong and could not be sent)
		' the caller is responsible to intercept it and display a message to the user
		Public Shared Sub SendInvitation(ByVal regPage As String, ByVal destinationEmail As String, ByVal customBody As String, ByVal inviter As User)
			'string from = inviter.Name + " " + inviter.LastName + "<" + inviter.Email + ">";
			Dim from As String = "<" + Constants.INVITATION_EMAIL + ">"
			Dim subj As String = Constants.INVITE_MAIL_SUBJECT.Replace(Constants.TXT_USER_NAME_TAG, inviter.Name + " " + inviter.LastName)
			Dim body As String = ComposeInviteMailBody(regPage, customBody, inviter)

			Utils.SendMail(from, destinationEmail, subj, body)
		End Sub

		' Compose the body of an invitation email
		' NOTE: public access, since it's used
		' in the "invite friend" page to visualize
		' the actual content of the email
		Public Shared Function ComposeInviteMailBody(ByVal regPage As String, ByVal customBody As String, ByVal inviter As User) As String
			Dim body As String = Constants.INVITE_MAIL_BODY

			' get the registration link in there
			Dim regLink As String = ComposeRegInviteLink(regPage, inviter)
			body = body.Replace(Constants.TXT_REG_LINK_TAG, regLink)

			' place the user name and email where appropriate
			body = body.Replace(Constants.TXT_USER_NAME_TAG, inviter.Name + " " + inviter.LastName)
			body = body.Replace(Constants.TXT_USER_EMAIL_TAG, inviter.Email)

			' insert the custom user text, if there was any
			Dim bodyToSend As String = customBody
			If bodyToSend = Nothing OrElse bodyToSend.Length = 0 Then
				bodyToSend = Constants.INVITE_BODY_NONE
			End If
			body = body.Replace(Constants.TXT_USER_TEXT_TAG, bodyToSend)

			Return body
		End Function

		' Send a password-reset-email to a new user
		Public Shared Sub SendPassResetEmail(ByVal passPage As String, ByVal usr As User)
			Dim [to] As String = "<" + usr.Email + ">"
			Dim subj As String = Constants.PASS_MAIL_SUBJECT

			Dim body As String = Constants.PASS_MAIL_BODY.Replace(Constants.TXT_USER_NAME_TAG, usr.Name)
			body = body.Replace(Constants.TXT_REG_LINK_TAG, ComposeRegConfirmLink(passPage, usr))
			body = body.Replace(Constants.TXT_DISCLAIMER_TEXT_TAG, ComposeNoSPAMDisclaimer(usr))

			Utils.SendMail(Constants.MESSAGES_EMAIL, [to], subj, body)
		End Sub

		' Send a registration confirmation email to a new user
		Public Shared Sub SendRegistraionConfirmation(ByVal confirmPage As String, ByVal usr As User)
			Dim [to] As String = "<" + usr.Email + ">"
			Dim subj As String = Constants.REG_MAIL_SUBJECT

			Dim body As String = Constants.REG_MAIL_BODY.Replace(Constants.TXT_USER_NAME_TAG, usr.Name)
			body = body.Replace(Constants.TXT_REG_LINK_TAG, ComposeRegConfirmLink(confirmPage, usr))
			body = body.Replace(Constants.TXT_DISCLAIMER_TEXT_TAG, ComposeNoSPAMDisclaimer(usr))

			Utils.SendMail(Constants.MESSAGES_EMAIL, [to], subj, body)
		End Sub

		' Send a user feedback
		Public Shared Sub SendFeedback(ByVal feedback As String, ByVal usr As User)
			Dim subj As String = Constants.FEEDBACK_MAIL_SUBJECT
			Dim body As String = Constants.FEEDBACK_MAIL_BODY

			body = body.Replace(Constants.TXT_USER_NAME_TAG, usr.Name)
			body = body.Replace(Constants.TXT_USER_EMAIL_TAG, usr.Email)

			Dim fbToSend As String = feedback
			If fbToSend = Nothing OrElse fbToSend.Length = 0 Then
				fbToSend = Constants.FEEDBACK_NONE
			End If
			body = body.Replace(Constants.TXT_USER_TEXT_TAG, fbToSend)

			Utils.SendMail(Constants.MESSAGES_EMAIL, Constants.MESSAGES_EMAIL, subj, body)
		End Sub

		' Computes the hash string, corresponding to a user's email/password
		Public Shared Function ComputeUserHash(ByVal userEmail As String, ByVal userPass As String) As String
			Dim passHash As String = ""

			If userPass.Length > 0 Then
				Dim data As String = userEmail + userPass
				Dim dataArrayUnicode As Byte() = Encoding.Unicode.GetBytes(data)

				Dim crypt As MD5 = New MD5CryptoServiceProvider()
				dataArrayUnicode = crypt.ComputeHash(dataArrayUnicode, 0, dataArrayUnicode.Length)

				passHash = Convert.ToBase64String(dataArrayUnicode)
			End If

			Return passHash
		End Function

		' Returns a string consisting of a random set of numbers
		Public Shared Function GetRandomPassword() As String
			Dim passBytes As Byte() = New Byte(Constants.INITIAL_PASS_LENGTH) {}

			Dim randGenerator As New Random(DateTime.Now.Millisecond)
			randGenerator.NextBytes(passBytes)

			Dim pass As String = Convert.ToBase64String(passBytes)

			Return pass
		End Function

		' Returns and existing invitation if such exists
		' Or a new one if it doesn't, with the inviter set to userID
		Public Shared Function GetFriendInvitation(ByVal userID As Integer, ByVal friendID As Integer) As DirectFriend
			Dim df As DirectFriend = Nothing

			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()
			Try
				Dim cmd As New SqlCommand("SELECT * FROM DirectFriends WHERE (UID=@UID AND FriendUID=@FriendUID) OR (FriendUID=@UID AND UID=@FriendUID)")
				cmd.Connection = conn
				cmd.Parameters.Add("@UID", userID)
				cmd.Parameters.Add("@FriendUID", friendID)

				Dim dr As SqlDataReader = cmd.ExecuteReader()
				If dr.Read() Then
					df = New DirectFriend(userID, dr)
				Else
					df = New DirectFriend(userID, friendID)
				End If

				dr.Close()
			Finally
				conn.Close()
			End Try

			Return df
		End Function


		Public Shared Function GetFriendInvitation(ByVal userID As Integer, ByVal friendID As Integer, ByVal isJoin As Boolean) As DirectFriend
			Dim df As DirectFriend = Nothing

			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()
			Try
				Dim cmd As New SqlCommand("SELECT * FROM DirectFriends WHERE (UID=@UID AND FriendUID=@FriendUID) OR (FriendUID=@UID AND UID=@FriendUID)")
				cmd.Connection = conn
				cmd.Parameters.Add("@UID", userID)
				cmd.Parameters.Add("@FriendUID", friendID)

				Dim dr As SqlDataReader = cmd.ExecuteReader()
				If dr.Read() Then
					df = New DirectFriend(userID, dr)
				Else
					df = New DirectFriend(userID, friendID, isJoin)
				End If

				dr.Close()
			Finally
				conn.Close()
			End Try

			Return df
		End Function

		' Finds a given number of randomly chosen
		' 2BMates users
		'
		' returns an unordered array list of unique Users objects
		Public Shared Function GetRandomUsers(ByVal cnt As Integer, ByVal onlyPeopleWithPhotos As Boolean) As ArrayList
			Dim allUsers As New ArrayList()

			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()

			Try
				' Build the users list
				Dim sqlString As String = "SELECT * FROM Users WHERE Status <> 2"
				If onlyPeopleWithPhotos = True Then
					sqlString += " AND DefaultPictureID IS NOT NULL"
				End If

				Dim cmdSelect As New SqlCommand(sqlString)
				cmdSelect.Connection = conn

				Dim dr As SqlDataReader = cmdSelect.ExecuteReader()

				' Read the users array
				While dr.Read()
					Dim u As New User(dr)
					allUsers.Add(u)
				End While

				dr.Close()
			Finally
				conn.Close()
			End Try

			'
			' Not choose a number of random users among those found
			'
			Dim allUsersCount As Integer = allUsers.Count
			cnt = Math.Min(cnt, allUsersCount)

			Dim users As New ArrayList()
			Dim hash As New Hashtable()
			Dim rnd As New Random()

			Dim foundCnt As Integer = 0
			While foundCnt < cnt
				Dim u As User = DirectCast(allUsers(rnd.[Next](allUsersCount)), User)

				If Not hash.Contains(u.ID) Then
					users.Add(u)
					hash(u.ID) = u.ID
					System.Math.Max(System.Threading.Interlocked.Increment(foundCnt),foundCnt - 1)
				End If
			End While

			Return users
		End Function

		' Finds a given number of randomly chosen
		' network users, that have a song URL
		'
		' returns an unordered array list of unique NetworkFriend objects
		'
		' NOTE: since not all users are loaded the path discovery wont work
		'		in order to discover the path at a later stage use the other
		'		function ( FindNetworkedUsers ) with the max path length set
		'		to the friend's distance
		'
		Public Shared Function FindRandomNetworkedUsersWithSongURL(ByVal userID As Integer, ByVal maxPath As Integer, ByVal usrCount As Integer, ByVal includeDirectFriends As Boolean) As ArrayList
			Dim allUsers As New ArrayList()

			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()
			Dim trans As SqlTransaction = conn.BeginTransaction()

			Try
				' Create the temporary table
				' and execute the find command
				BuildNetworkFriendsTMPTable(userID, maxPath, trans)

				' Build the users list
				Dim cmdSelect As New SqlCommand(GetNetworkedFriendsWithSongURLSQL())
				cmdSelect.Connection = conn
				cmdSelect.Transaction = trans

				Dim dr As SqlDataReader = cmdSelect.ExecuteReader()


				' Read the users array
				While dr.Read()
					Dim nf As New NetworkFriend(userID, dr, Nothing)

					' Skip direct friends if requested
					If Not includeDirectFriends AndAlso (nf.PathLength <= 1) Then
						Continue While
					End If

					allUsers.Add(nf)
				End While

				dr.Close()


				' Drop the temporary table
				DropNetworkFriendsTMPTable(trans)

				trans.Commit()
			Catch generatedExceptionName As Exception
				trans.Rollback()
				Throw
			Finally
				conn.Close()
			End Try

			'
			' Not choose a number of random users among those found
			'
			Dim allUsersCount As Integer = allUsers.Count
			usrCount = Math.Min(usrCount, allUsersCount)

			Dim users As New ArrayList()
			Dim hash As New Hashtable()
			Dim rnd As New Random()

			Dim foundCnt As Integer = 0
			While foundCnt < usrCount
				Dim nf As NetworkFriend = DirectCast(allUsers(rnd.[Next](allUsersCount)), NetworkFriend)

				If Not hash.Contains(nf.FriendID) Then
					users.Add(nf)
					hash(nf.FriendID) = nf.FriendID
					System.Math.Max(System.Threading.Interlocked.Increment(foundCnt),foundCnt - 1)
				End If
			End While

			Return users
		End Function

		' Find random users with song url entered
		Public Shared Function FindRandomUsersWithSongURL(ByVal usrCount As Integer) As ArrayList
			Dim allUsers As New ArrayList()

			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()

			Try
				' Build the users list
				Dim cmdSelect As New SqlCommand(GetUsersWithSongURLSQL())
				cmdSelect.Connection = conn

				Dim dr As SqlDataReader = cmdSelect.ExecuteReader()

				' Read the users array
				While dr.Read()
					Dim u As New User(dr)
					allUsers.Add(u)
				End While


				dr.Close()
			Catch generatedExceptionName As Exception
				Throw
			Finally
				conn.Close()
			End Try

			'
			' Not choose a number of random users among those found
			'
			Dim allUsersCount As Integer = allUsers.Count
			usrCount = Math.Min(usrCount, allUsersCount)

			Dim users As New ArrayList()
			Dim hash As New Hashtable()
			Dim rnd As New Random()

			Dim foundCnt As Integer = 0
			While foundCnt < usrCount
				Dim us As User = DirectCast(allUsers(rnd.[Next](allUsersCount)), User)

				If Not hash.Contains(us.ID) Then
					users.Add(us)
					hash(us.ID) = us.ID
					System.Math.Max(System.Threading.Interlocked.Increment(foundCnt),foundCnt - 1)
				End If
			End While

			Return users
		End Function

		' Finds the newest friend-networked users at or below the given
		' maximum distance to the given user
		'
		' returns an array list of NetworkFriend objects
		' ordered ascending by date the user joined, PathLength
		'
		' NOTE: since the users are not ordered by path length
		'		the path discovery would work, or at least won't be effective
		'		in order to discover the path at a later stage use the other
		'		function ( FindNetworkedUsers ) with the max path length set
		'		to the friend's distance
		'
		Public Shared Function FindNewNetworkedUsers(ByVal userID As Integer, ByVal maxPath As Integer, ByVal usrCount As Integer, ByVal includeDirectFriends As Boolean) As ArrayList
			Dim users As New ArrayList()

			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()
			Dim trans As SqlTransaction = conn.BeginTransaction()

			Try
				' Create the temporary table
				' and execute the find command
				BuildNetworkFriendsTMPTable(userID, maxPath, trans)

				' Build the users list
				Dim cmdSelect As New SqlCommand(GetNewestNetworkedFriendsSQL())
				cmdSelect.Connection = conn
				cmdSelect.Transaction = trans

				Dim dr As SqlDataReader = cmdSelect.ExecuteReader()


				' Read the users array
				Dim curCount As Integer = 1
				While dr.Read() AndAlso curCount < usrCount
					Dim nf As New NetworkFriend(userID, dr, Nothing)

					' Skip direct friends if requested
					If Not includeDirectFriends AndAlso (nf.PathLength <= 1) Then
						Continue While
					End If

					users.Add(nf)
					System.Math.Max(System.Threading.Interlocked.Increment(curCount),curCount - 1)
				End While

				dr.Close()


				' Drop the temporary table
				DropNetworkFriendsTMPTable(trans)

				trans.Commit()
			Catch generatedExceptionName As Exception
				trans.Rollback()
				Throw
			Finally
				conn.Close()
			End Try

			Return users
		End Function

		' Finds the friend-networked users at or below the given maximum distance to the given user
		' returns a hashtable of <friend ID, NetworkFriend object>
		Public Shared Function FindHashNetworkedUsers(ByVal userID As Integer, ByVal maxPath As Integer, ByVal includeDirectFriends As Boolean) As Hashtable
			Dim hashNU As New Hashtable()
			Dim arrNU As ArrayList = FindNetworkedUsers(userID, maxPath, includeDirectFriends)
			For Each nf As NetworkFriend In arrNU
				hashNU(nf.FriendID) = nf
			Next

			Return hashNU
		End Function

		' Finds the friend-networked users at or below the given maximum distance to the given user
		' returns a list of NetworkFriend objects ordered ascending by PathLength
		Public Shared Function FindNetworkedUsers(ByVal userID As Integer, ByVal maxPath As Integer, ByVal includeDirectFriends As Boolean) As ArrayList
			Dim users As New ArrayList()

			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()
			Dim trans As SqlTransaction = conn.BeginTransaction()

			Try
				' Create the temporary table
				' and execute the find command
				BuildNetworkFriendsTMPTable(userID, maxPath, trans)

				' Build the users list
				' NOTE: ascending sort on level is required for the path discovery to work!
				Dim cmdSelect As New SqlCommand("SELECT * FROM #NetworkFriends ORDER BY PathLength ASC")
				cmdSelect.Connection = conn
				cmdSelect.Transaction = trans

				Dim dr As SqlDataReader = cmdSelect.ExecuteReader()

				Dim ordParent As Integer = dr.GetOrdinal("ParentFriendUID")

				Dim usersHash As New Hashtable()
				While dr.Read()
					Dim parent As NetworkFriend = Nothing
					If Not dr.IsDBNull(ordParent) Then
						parent = DirectCast(usersHash(dr.GetInt32(ordParent)), NetworkFriend)
					End If

					Dim [friend] As New NetworkFriend(userID, dr, parent)
					usersHash([friend].FriendID) = [friend]

					' Skip direct friends if requested
					If Not includeDirectFriends AndAlso ([friend].PathLength <= 1) Then
						Continue While
					End If

					users.Add([friend])
				End While
				dr.Close()

				' Drop the temporary table
				DropNetworkFriendsTMPTable(trans)

				trans.Commit()
			Catch generatedExceptionName As Exception
				trans.Rollback()
				Throw
			Finally
				conn.Close()
			End Try

			Return users
		End Function

		' Returns the users found by the search criteria
		Public Shared Function FindUsers(ByVal filter As UserFilter) As ArrayList
			Dim users As New ArrayList()

			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()

			Try
				Dim cmd As SqlCommand = GetFindUsersCMD(filter)
				cmd.Connection = conn

				Dim dr As SqlDataReader = cmd.ExecuteReader()
				While dr.Read()
					users.Add(New User(dr))
				End While
			Finally
				conn.Close()
			End Try

			Return users
		End Function

		Protected Shared Function LoginUserByCmdPassHash(ByVal cmd As SqlCommand, ByVal passHash As String) As User
			Dim usr As User = GetUserByCmd(cmd)

			If usr <> Nothing Then
				' Verify the user's password
				If Not passHash.Equals(usr.PassHash) Then
					usr = Nothing
				End If
			End If

			If usr <> Nothing Then
				' Check the status of the user account
				If usr.Status = STATUS_LOCKED Then
					usr = Nothing
				End If
			End If

			If usr <> Nothing Then
				' Logged in! Update last login date

				Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()

				Try
					Dim cmdLastLogin As New SqlCommand("UPDATE Users SET LastLoginDate=@LastLoginDate WHERE ID=@ID")
					cmdLastLogin.Connection = conn

					cmdLastLogin.Parameters.Add("@LastLoginDate", DateTime.Now)
					cmdLastLogin.Parameters.Add("@ID", usr.ID)

					cmdLastLogin.ExecuteNonQuery()
				Finally
					conn.Close()
				End Try
			End If

			Return usr
		End Function

		' Builds an SQL returning from the already build
		' list of networked friends, those that have a SongURL
		Protected Shared Function GetNetworkedFriendsWithSongURLSQL() As String
			Dim sql As String = "SELECT nf.*, usr.*" + Environment.NewLine
			sql += "FROM" + Environment.NewLine
			sql += "" & Chr(9) & "#NetworkFriends nf," + Environment.NewLine
			sql += "" & Chr(9) & "Users usr" + Environment.NewLine
			sql += "WHERE" + Environment.NewLine
			sql += "" & Chr(9) & "nf.FriendUID = usr.ID" + Environment.NewLine
			sql += "" & Chr(9) & "AND (" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "LEN(usr.SongURL1) > 0" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "OR LEN(usr.SongURL2) > 0" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "OR LEN(usr.SongURL3) > 0)" + Environment.NewLine
			Return sql
		End Function

		' Get userswith song url

		Protected Shared Function GetUsersWithSongURLSQL() As String
			Dim sql As String = "SELECT usr.*," + Environment.NewLine
			sql += "" & Chr(9) & "usrPics.picCount" + Environment.NewLine
			sql += "FROM" + Environment.NewLine
			sql += "" & Chr(9) & "Users usr," + Environment.NewLine
			sql += "" & Chr(9) & "(SELECT usr.ID, COUNT( pic.ID ) AS picCount" + Environment.NewLine
			sql += "" & Chr(9) & "FROM" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "Users usr" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "LEFT OUTER JOIN Pictures pic" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "ON usr.ID = pic.UID" + Environment.NewLine
			sql += "" & Chr(9) & "GROUP BY usr.ID) AS usrPics" + Environment.NewLine
			sql += "WHERE" + Environment.NewLine
			sql += "" & Chr(9) & "usr.ID = usrPics.ID" + Environment.NewLine
			sql += "" & Chr(9) & "AND usr.DefaultPictureID IS NOT NULL" + Environment.NewLine
			sql += "" & Chr(9) & "AND (" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "LEN(usr.SongURL1) > 0" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "OR LEN(usr.SongURL2) > 0" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "OR LEN(usr.SongURL3) > 0)" + Environment.NewLine
			sql += "" & Chr(9) & "AND" & Chr(9) & "usr.Status <> 2" + Environment.NewLine
			Return sql
		End Function

		' Builds an SQL returning the already build
		' list of networked friends, ordered by date joined
		Protected Shared Function GetNewestNetworkedFriendsSQL() As String
			Dim sql As String = "SELECT nf.*, usr.*" + Environment.NewLine
			sql += "FROM" + Environment.NewLine
			sql += "" & Chr(9) & "#NetworkFriends nf," + Environment.NewLine
			sql += "" & Chr(9) & "Users usr" + Environment.NewLine
			sql += "WHERE" + Environment.NewLine
			sql += "" & Chr(9) & "nf.FriendUID = usr.ID" + Environment.NewLine
			sql += "ORDER BY" + Environment.NewLine
			sql += "" & Chr(9) & "usr.Date DESC, nf.PathLength ASC" + Environment.NewLine
			Return sql
		End Function

		' Creates a temporary table to store networked users found in it
		' NOTE: the caller is responsible to DropNetworkFriendsTMPTable
		' as soon as possible after finished with this table
		Protected Shared Sub BuildNetworkFriendsTMPTable(ByVal userID As Integer, ByVal maxPath As Integer, ByVal trans As SqlTransaction)
			' Create the temporary table
			Dim cmdCreate As New SqlCommand(GetNetworkFriendsTableSQL())
			cmdCreate.Connection = trans.Connection
			cmdCreate.Transaction = trans
			cmdCreate.ExecuteNonQuery()


			' Execute the find command
			Dim cmdFind As New SqlCommand("GetNetworkFriends")
			cmdFind.Connection = trans.Connection
			cmdFind.Transaction = trans

			cmdFind.CommandType = CommandType.StoredProcedure
			cmdFind.Parameters.Add("@UID", userID)
			cmdFind.Parameters.Add("@Level", maxPath)

			cmdFind.ExecuteNonQuery()
		End Sub

		' Drops the temporary table used to store networked friends
		Protected Shared Sub DropNetworkFriendsTMPTable(ByVal trans As SqlTransaction)
			' Drop the temporary table
			Dim cmdDrop As New SqlCommand("DROP TABLE #NetworkFriends")
			cmdDrop.Connection = trans.Connection
			cmdDrop.Transaction = trans
			cmdDrop.ExecuteNonQuery()
		End Sub

		' Composes the SQL string creating the temporary table
		' to collect networked users in
		Protected Shared Function GetNetworkFriendsTableSQL() As String
			Dim sql As String = "CREATE TABLE #NetworkFriends (" + Environment.NewLine
			sql += "" & Chr(9) & "[UID] [int] NOT NULL ," + Environment.NewLine
			sql += "" & Chr(9) & "[FriendUID] [int] NOT NULL ," + Environment.NewLine
			sql += "" & Chr(9) & "[PathLength] [int] NOT NULL," + Environment.NewLine
			sql += "" & Chr(9) & "[ParentFriendUID] [int]" + Environment.NewLine
			sql += ") ON [PRIMARY]" + Environment.NewLine
			sql += "" + Environment.NewLine
			sql += "ALTER TABLE #NetworkFriends WITH NOCHECK ADD " + Environment.NewLine
			sql += "" & Chr(9) & "CONSTRAINT [PK_NetworkFriends] PRIMARY KEY  CLUSTERED " + Environment.NewLine
			sql += "" & Chr(9) & "(" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "[UID]," + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "[FriendUID]" + Environment.NewLine
			sql += "" & Chr(9) & ")  ON [PRIMARY] " + Environment.NewLine
			sql += "" + Environment.NewLine
			sql += " CREATE  INDEX [IX_NetworkFriends] ON #NetworkFriends([UID]) ON [PRIMARY]" + Environment.NewLine
			Return sql
		End Function


		' Composes the SQL string that matches the users,
		' according to the given search criteria
		'
		' NOTE: take care keep in sync the params with GetFindUsersSQL
		'
		Protected Shared Function GetFindUsersCMD(ByVal filter As UserFilter) As SqlCommand
			Dim cmd As New SqlCommand(GetFindUsersSQL(filter))

			' commented by ivan. bellow is a fix for browse page
'			if ( filter.ageFrom > UserFilter.minAge )
'				cmd.Parameters.Add( "@DOBMax", DateTime.Now.AddYears( -filter.ageFrom ) );
'			if ( filter.ageTo < UserFilter.maxAge )
'				cmd.Parameters.Add( "@DOBMin", DateTime.Now.AddYears( -filter.ageTo ) );
'			

			If filter.ageMetters = True Then
				cmd.Parameters.Add("@DOBMax", filter.ageTo)
				'cmd.Parameters.Add( "@DOBMax", DateTime.Now.AddYears( -filter.ageFrom ) );
					'cmd.Parameters.Add( "@DOBMin", DateTime.Now.AddYears( -filter.ageTo ) );
				cmd.Parameters.Add("@DOBMin", filter.ageFrom)
			End If
			If filter.email <> Nothing AndAlso filter.email.Length > 0 Then
				cmd.Parameters.Add("@Email", filter.email)
			End If

			Return cmd
		End Function

		' Composes the SQL string that matches the users,
		' according to the given search criteria
		'
		' NOTE: take care to keep in sync the params with GetFindUsersCMD
		'
		Protected Shared Function GetFindUsersSQL(ByVal filter As UserFilter) As String
			Dim sql As String = "SELECT" + Environment.NewLine
			sql += "" & Chr(9) & "usr.*," + Environment.NewLine
			sql += "" & Chr(9) & "usrPics.picCount" + Environment.NewLine
			sql += "FROM" + Environment.NewLine
			sql += "" & Chr(9) & "Users usr," + Environment.NewLine
			sql += "" & Chr(9) & "(SELECT usr.ID, COUNT( pic.ID) AS picCount" + Environment.NewLine
			sql += "" & Chr(9) & "FROM" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "Users usr" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "LEFT OUTER JOIN Pictures pic" + Environment.NewLine
			sql += "" & Chr(9) & "" & Chr(9) & "ON usr.ID = pic.UID" + Environment.NewLine
			sql += "" & Chr(9) & "GROUP BY usr.ID) AS usrPics" + Environment.NewLine
			sql += "WHERE" + Environment.NewLine
			sql += "" & Chr(9) & "usr.ID = usrPics.ID" + Environment.NewLine
			sql += " AND usr.Status <> 2" + Environment.NewLine

			' Put the conditions here
			If filter.hasPhoto Then
				sql += "" & Chr(9) & "AND usrPics.picCount > 0" + Environment.NewLine
			End If

			If filter.hasFavSong Then
				sql += "" & Chr(9) & "AND (len(usr.SongURL1) > 0" + Environment.NewLine
				sql += "" & Chr(9) & "" & Chr(9) & "OR len(usr.SongURL2) > 0" + Environment.NewLine
				sql += "" & Chr(9) & "" & Chr(9) & "OR len(usr.SongURL3) > 0)" + Environment.NewLine
			End If

			If filter.gender <> UserFilter.Gender.ufgAny Then
				sql += "" & Chr(9) & "AND usr.Gender = " + DirectCast(filter.gender, Integer) + Environment.NewLine
			End If
			If filter.genderPreference <> UserFilter.GenderPreference.ufgpAny Then
				sql += "" & Chr(9) & "AND usr.GenderPreference = " + DirectCast(filter.genderPreference, Integer) + Environment.NewLine
			End If

			Dim genSQL As String = GetGeneralSearchSQL("usr", filter.general)
			If genSQL.Length > 0 Then
				sql += "AND (" + genSQL + ")" + Environment.NewLine
			End If

			Dim msSQL As String = GetMaritalStatusSQL("usr", filter.status)
			If msSQL.Length > 0 Then
				sql += "AND (" + msSQL + ")" + Environment.NewLine
			End If

			Dim apSQL As String = GetActivityPreferenceSQL("usr", filter.activityPreference)
			If apSQL.Length > 0 Then
				sql += "AND (" + apSQL + ")" + Environment.NewLine
			End If

			sql += GetLikeFilterSQL("usr.Name", filter.name)
			sql += GetLikeFilterSQL("usr.LastName", filter.lastName)
			sql += GetLikeFilterSQL("usr.Interests", filter.interests)

			sql += GetLikeFilterSQL("usr.AboutMe", filter.aboutMe)
			sql += GetLikeFilterSQL("usr.LookingFor", filter.lookingFor)
			sql += GetLikeFilterSQL("usr.Affiliations", filter.affiliations)
			sql += GetLikeFilterSQL("usr.Companies", filter.companies)
			sql += GetLikeFilterSQL("usr.Schools", filter.schools)
			sql += GetLikeFilterSQL("usr.Music", filter.music)
			sql += GetLikeFilterSQL("usr.Books", filter.books)
			sql += GetLikeFilterSQL("usr.TV", filter.tv)
			sql += GetLikeFilterSQL("usr.Movies", filter.movies)
			sql += GetLikeFilterSQL("usr.Occupation", filter.occupation)
			sql += GetLikeFilterSQL("usr.City", filter.city)
			If filter.countryID >= 0 Then
				sql += "" & Chr(9) & "AND usr.CountryID = " + filter.countryID.ToString() + Environment.NewLine
			End If

			' NOTE : The following are command parameters, if needed
			' since manual string convertion is not recommended for
			' this data types (e.g. Date, String), because of different formats and/or escaping issues

			' commented by ivan. bellow is a fix for browse page
'			if ( filter.ageFrom > UserFilter.minAge )
'				sql += "	AND usr.Date_of_birth <= @DOBMax" + Environment.NewLine;
'			if ( filter.ageTo < UserFilter.maxAge )
'				sql += "	AND usr.Date_of_birth >= @DOBMin" + Environment.NewLine;
'			

			If filter.ageMetters = True Then

				sql += "" & Chr(9) & "AND datediff(yy, usr.Date_of_birth, getdate()) - " + " (case when (datepart(m, usr.Date_of_birth) > datepart(m, getdate())) or " + "" & Chr(9) & "     (datepart(m, usr.Date_of_birth) = datepart(m, getdate()) And datepart(d, usr.Date_of_birth) > datepart(d, getdate())) " + "" & Chr(9) & "then 1 " + "" & Chr(9) & "else 0 " + " end) <= @DOBMax " + Environment.NewLine


					'sql += "	AND usr.Date_of_birth <= @DOBMax" + Environment.NewLine;
					'sql += "	AND usr.Date_of_birth >= @DOBMin" + Environment.NewLine;
				sql += "" & Chr(9) & "AND datediff(yy, usr.Date_of_birth, getdate()) - " + " (case when (datepart(m, usr.Date_of_birth) > datepart(m, getdate())) or " + "" & Chr(9) & "     (datepart(m, usr.Date_of_birth) = datepart(m, getdate()) And datepart(d, usr.Date_of_birth) > datepart(d, getdate())) " + "" & Chr(9) & "then 1 " + "" & Chr(9) & "else 0 " + " end) >= @DOBMin " + Environment.NewLine
			End If

			If filter.email <> Nothing AndAlso filter.email.Length > 0 Then
				sql += "" & Chr(9) & "AND usr.Email = @Email" + Environment.NewLine
			End If

			'sql += "ORDER BY Name, LastName, Email" + Environment.NewLine;
			If filter.orderBy = UserFilter.OrderBy.recentlyUpdated Then
				sql += "ORDER BY LastEditedDate Desc" + Environment.NewLine
ElseIf filter.orderBy = UserFilter.OrderBy.lastLogin Then
				sql += "ORDER BY LastLoginDate Desc" + Environment.NewLine
ElseIf filter.orderBy = UserFilter.OrderBy.newUsers Then
				sql += "ORDER BY [Date] Desc" + Environment.NewLine
			Else
				sql += "ORDER BY Name, LastName, Email" + Environment.NewLine
			End If

			Return sql
		End Function

		' Compose an SQL where clause condition to match
		' a field to a string, using a LIKE clause
		Protected Shared Function GetLikeFilterSQL(ByVal usrTblAlias As String, ByVal filter As String) As String
			If filter <> Nothing AndAlso filter.Length > 0 Then
				Return "" & Chr(9) & "AND " + usrTblAlias + " " + Utils.GetLikeSQL(filter) + Environment.NewLine
			Else
				Return ""
			End If
		End Function

		' Composes an SQL where clause condition to match
		' the given general search filter
		' - if no preferences returns an empty string;
		' - matches the following fields:
		' "Interests"
		' "Music"
		' "Books"
		' "Movies"
		' "Affiliations"
		' "Companies"
		' "Schools"
		Protected Shared Function GetGeneralSearchSQL(ByVal usrTblAlias As String, ByVal filter As String) As String
			Dim sql As String = ""

			If filter <> Nothing AndAlso filter.Length > 0 Then
				sql = "" & Chr(9) & "" + usrTblAlias + ".Interests " + Utils.GetLikeSQL(filter) + Environment.NewLine
				sql += "" & Chr(9) & "OR " + usrTblAlias + ".Music " + Utils.GetLikeSQL(filter) + Environment.NewLine
				sql += "" & Chr(9) & "OR " + usrTblAlias + ".Books " + Utils.GetLikeSQL(filter) + Environment.NewLine
				sql += "" & Chr(9) & "OR " + usrTblAlias + ".Movies " + Utils.GetLikeSQL(filter) + Environment.NewLine
				sql += "" & Chr(9) & "OR " + usrTblAlias + ".Affiliations " + Utils.GetLikeSQL(filter) + Environment.NewLine
				sql += "" & Chr(9) & "OR " + usrTblAlias + ".Companies " + Utils.GetLikeSQL(filter) + Environment.NewLine
				sql += "" & Chr(9) & "OR " + usrTblAlias + ".Schools " + Utils.GetLikeSQL(filter) + Environment.NewLine
				sql += "" & Chr(9) & "OR " + usrTblAlias + ".Occupation " + Utils.GetLikeSQL(filter) + Environment.NewLine
			End If

			Return sql
		End Function

		' Composes an SQL where clause condition to match
		' the given merital status filter
		' - if no preferences returns an empty string;
		Protected Shared Function GetMaritalStatusSQL(ByVal usrTblAlias As String, ByVal ms As UserFilter.MeritalStatus) As String
			Dim msExists As Boolean = False
			Dim sql As String = ""

			If ms.unspecified Then
				sql = usrTblAlias + ".MeritalStatus = 0" + Environment.NewLine
				msExists = True
			End If

			If ms.[single] Then
				' Single/Separated/Divorced
				If msExists Then
					sql += "OR "
				End If
				sql += usrTblAlias + ".MeritalStatus = 1" + Environment.NewLine
				msExists = True
			End If

			If ms.relationship Then
				If msExists Then
					sql += "OR "
				End If
				sql += usrTblAlias + ".MeritalStatus = 2" + Environment.NewLine
				msExists = True
			End If

			If ms.openRelationship Then
				If msExists Then
					sql += "OR "
				End If
				sql += usrTblAlias + ".MeritalStatus = 3" + Environment.NewLine
				msExists = True
			End If

			If ms.married Then
				If msExists Then
					sql += "OR "
				End If
				sql += usrTblAlias + ".MeritalStatus = 4" + Environment.NewLine
				msExists = True
			End If

			If ms.openMarriage Then
				If msExists Then
					sql += "OR "
				End If
				sql += usrTblAlias + ".MeritalStatus = 5" + Environment.NewLine
				msExists = True
			End If

			Return sql
		End Function

		' Composes an SQL where clause condition to match
		' the given activity preferences
		' - if no preferences returns an empty string;
		Protected Shared Function GetActivityPreferenceSQL(ByVal usrTblAlias As String, ByVal ap As UserFilter.ActivityPreference) As String
			Dim apExists As Boolean = False
			Dim sql As String = ""

			If ap.dating Then
				' Dating - Mates_Dating
				sql = usrTblAlias + ".Mates_Dating = 1" + Environment.NewLine
				apExists = True
			End If

			If ap.relationship Then
				' Serious Relationship - Mates_SR
				If apExists Then
					sql += "OR "
				End If
				sql += usrTblAlias + ".Mates_SR = 1" + Environment.NewLine
				apExists = True
			End If

			If ap.friends Then
				' Friends - Mates_Friends
				If apExists Then
					sql += "OR "
				End If
				sql += usrTblAlias + ".Mates_Friends = 1" + Environment.NewLine
				apExists = True
			End If

			If ap.partners Then
				' Activity Partners - Mates_AP
				If apExists Then
					sql += "OR "
				End If
				sql += usrTblAlias + ".Mates_AP = 1" + Environment.NewLine
				apExists = True
			End If

			If ap.penpals Then
				' Penpals - Mates_Pen
				If apExists Then
					sql += "OR "
				End If
				sql += usrTblAlias + ".Mates_Pen = 1" + Environment.NewLine
				apExists = True
			End If

			If ap.hangout Then
				' Just hanging out - Mates_JHO
				If apExists Then
					sql += "OR "
				End If
				sql += usrTblAlias + ".Mates_JHO = 1" + Environment.NewLine
				apExists = True
			End If

			Return sql
		End Function

		' Return a standard disclaimer text (with appropriate links for the user to update his account settings)
		Public Shared Function ComposeNoSPAMDisclaimer(ByVal usr As User) As String
			Dim accURL As String = Constants.APPLICATION_URL
			If usr <> Nothing Then
				accURL = ComposeAccountSettingsLink(Constants.APPLICATION_URL + "/" + Constants.ACCOUNT_SETTINGS_PAGE, usr)
			End If
			Dim disclaimerText As String = Constants.NO_SPAM_DISCLAIMER.Replace(Constants.TXT_ACC_LINK_TAG, accURL)
			disclaimerText = disclaimerText.Replace(Constants.TXT_PRIVACY_MAIL_LINK, ComposeEMailLink(Constants.PRIVACY_EMAIL))
			Return disclaimerText
		End Function

		Protected Shared Function ComposeFriendRequestLink(ByVal request As DirectFriend) As String
			Return Constants.APPLICATION_URL + "/" + Constants.ADD_FRIEND_CONFIRMATION_PAGE + "?id=" + request.UserID
		End Function

		Protected Shared Function ComposeMailLink(ByVal msgID As Integer) As String
			Return Constants.APPLICATION_URL + "/" + Constants.VIEW_MESSAGE + "?id=" + msgID
		End Function

		Protected Shared Function ComposeCommentLink() As String
			Return Constants.APPLICATION_URL + "/" + Constants.FRIENDS_COMMENTS_PAGE
		End Function

		' NOTE: for now this link directs to the main blog page (not the particular comment)
		' the VIEW_BLOG_COMMENTS page probably needs to support
		' one more argument (e.g. entry id) and scroll to it, if supplied
		' additionally this is a just sent blog and it's ID is not know to us yet
		' (just the parentID is known) - if this is needed
		' a new stored procedure would be needed that
		' saves it (INSERT) and returns it's ID. It sould be used in the Blog.Send() method
		' instead of calling the direct "INSERT" statement
		Protected Shared Function ComposeBlogLink(ByVal be As Blog) As String
			Return Constants.APPLICATION_URL + "/" + Constants.VIEW_BLOG_COMMENTS + "?id=" + be.ParentBlogID
		End Function

		' Returns a link that logins a user and enters the user preferences page
		Protected Shared Function ComposeAccountSettingsLink(ByVal accPage As String, ByVal usr As User) As String
			Return accPage + "?" + ComposeURLLoginParams(usr)
		End Function

		' Returns a link to send to a user to join the site
		Protected Shared Function ComposeRegInviteLink(ByVal regPage As String, ByVal inviter As User) As String
			Dim regUrl As String = regPage
			regUrl += "?" + Constants.REGISTRATION_PARAM_REFERER + "=" + System.Web.HttpUtility.UrlEncode(inviter.Email)
			Return regUrl
		End Function

		' Returns a link to send to a user to confirm his registration
		Protected Shared Function ComposeRegConfirmLink(ByVal confirmPage As String, ByVal usr As User) As String
			Dim confirmUrl As String = confirmPage

			confirmUrl += "?" + Constants.REGISTRATION_CONFIRM_PARAM_ACTION + "=" + Constants.REGISTRATION_CONFIRM_PARAM_ACTION_VALUE
			confirmUrl += "&" + ComposeURLLoginParams(usr)

			Return confirmUrl
		End Function

		' Returns link parameters that login the user automatically
		Public Shared Function ComposeURLLoginParams(ByVal usr As User) As String
			Dim confirmUrlPrams As String = Constants.LOGIN_PARAM_USER + "=" + System.Web.HttpUtility.UrlEncode(usr.Email) + "&" + Constants.LOGIN_PARAM_KEY + "=" + System.Web.HttpUtility.UrlEncode(usr.PassHash)
			Return confirmUrlPrams
		End Function

		' Returns link to members page if user hadn't canceled its account
		' otherwise returns returns link to return message
		Public Shared Function ComposeMemeberLink(ByVal usr As User) As String
			Dim link As String = String.Empty
			If usr.Status <> Users.STATUS_LOCKED Then
				link = String.Format(Constants.LINK_MEMBER_ACTIVE, Constants.MEMBERS, usr.ID)
			Else
				link = String.Format(Constants.LINK_MEMBER_CANCELED, Constants.MEMBERS, usr.ID)
			End If

			Return link
		End Function

		' Returns JScript according to members link
		Public Shared Function ComposeMemeberLinkOnClickJS(ByVal usr As User, ByVal control As System.Web.UI.Control) As String
			Dim script As String = String.Empty
			If usr.Status <> Users.STATUS_LOCKED Then
				script = Constants.SCRIPT_LINK_MEMBER_ACTIVE
			Else
				script = String.Format(Constants.SCRIPT_LINK_MEMBER_CANCELED, control.UniqueID.Replace(":", "_"))
			End If

			Return script
		End Function

		Public Shared Function ComposeEMailLink(ByVal email As String) As String
			Dim mail_link As String = String.Format("{0}", email)
			'string.Format("<a href='{0}:{1}'>{2}</a>", "mailto", email, email );
			Return mail_link
		End Function

		' Retrieve the user using the given SQL command object
		' return null if no user found
		' NOTE: asserts that only one user is selected
		'		for more users user another method
		Protected Shared Function GetUserByCmd(ByVal cmd As SqlCommand) As User
			Dim usr As User = Nothing

			Dim conn As SqlConnection = DBManager.GetUnmanagedConnection()

			Try
				cmd.Connection = conn
				Dim dr As SqlDataReader = cmd.ExecuteReader()

				If dr.Read() Then
					usr = New User(dr)
					Debug.Assert(Not dr.Read())
				End If

				dr.Close()
			Finally
				conn.Close()
			End Try

			Return usr
		End Function

		Protected Shared Function LoginForumUser(ByVal userEmail As String, ByVal userPass As String) As Boolean
			Dim sPassword As String = ComputeUserHash(userEmail.ToLower(), userPass)
			'FormsAuthentication.HashPasswordForStoringInConfigFile(userPass,"md5");
			Dim userID As Object = Nothing
			Using cmd As New SqlCommand("yaf_user_login")
				cmd.CommandType = CommandType.StoredProcedure
				cmd.Parameters.Add("@BoardID", Constants.FORUM_BOARD_ID)
				cmd.Parameters.Add("@Name", userEmail)
				cmd.Parameters.Add("@Password", sPassword)
				Using conn As SqlConnection = DBManager.GetUnmanagedForumDBConnection()
					Try
						Using trans As SqlTransaction = conn.BeginTransaction()
							cmd.Connection = conn
							cmd.Transaction = trans
							userID = cmd.ExecuteScalar()
							trans.Commit()
						End Using
					Catch generatedExceptionName As Exception
					Finally
						conn.Close()
					End Try
				End Using
			End Using

			'object userID = DB.user_login(Constants.FORUM_BOARD_ID,userEmail,sPassword);
			If userID <> DBNull.Value Then
				Dim idName As String = String.Format("{0};{1};{2}", userID, Constants.FORUM_BOARD_ID, userEmail)
				FormsAuthentication.SetAuthCookie(idName, False)
				Return True
			End If
			Return False
		End Function

		Protected Shared Sub UpdateUserEmailToLower(ByVal usrMail As String, ByVal pass As String)
			Dim usr As User = Users.GetUserByEmail(usrMail)
			If (usr <> Nothing) AndAlso Not usr.Email.Equals(usr.Email.ToLower()) Then
				Dim passHash As String = ComputeUserHash(usr.Email.ToLower(), pass)
				usr.Email = usr.Email.ToLower()
				'usr.Save();
				usr.Password = pass
				usr.Save()
			End If
			'return usr;
		End Sub
	End Class
End Namespace






